/*
 * Tweenable.h
 *
 *  Created on: 2009/02/04
 *      Author: Yongshik Cho
 */

#ifndef TWEENABLE_H_
#define TWEENABLE_H_

#include <vector>
#include <map>
#include "../core/Prerequisites.h"
#include "../core/Vector2D.h"
#include "../core/ISlot.h"
#include "../core/ISignal_v5.h"
#include "../event/TweenEvent.h"
#include "Tickable.h"
#include "Renderable.h"
#include "sqplus/sqplus.h"
using namespace SqPlus;


class TweenFrame
{
public:
	TweenFrame(const uint32 time, const Vector2D& position, const float rotation, const Vector2D& scale, const Color& color)
	{
		mTime = time;
		mPosition = position;
		mRotation = rotation;
		mScale = scale;
		mColor = color;
	}
	virtual ~TweenFrame() {}

public:
	inline const uint32 getTime() const { return mTime; }
	inline const Vector2D& getPosition() const { return mPosition; }
	inline const float getRotation() const { return mRotation; }
	inline const Vector2D& getScale() const { return mScale; }
	inline const Color& getColor() const { return mColor; }

private:
	uint32 		mTime;
	Vector2D	mPosition;
	float		mRotation;
	Vector2D	mScale;
	Color		mColor;
};

class Tweenable : public Tickable
{
public:
	enum LOOP_TYPE
	{
		LOOP_COUNT,
		ENDLESS
	};

public:
	Tweenable(uint8 loopType = LOOP_COUNT, uint32 loopCount = 1);
	virtual ~Tweenable();

public:
	void addFrame(const TweenFrame& frame);
	void subFrame(const TweenFrame* frame);
	const uint32 getFrameCount() const { return (uint32)mFrames.size(); }

	void addRenderable(Renderable* r);
	void subRenderable(Renderable* r);
	Renderable* getRenderable(const uint32 index);
	const uint32 getRenderableCount() const { return (uint32)mRenderables.size(); }

	inline TweenFrame* getFrame(const uint32 index)
	{
		if(index >= mFrames.size())
			return 0;

		return &mFrames[index];
	}
	inline TweenFrame* getFrame()
	{
		if(mIndex >= mFrames.size())
			return 0;

		return &mFrames[mIndex];
	}

	inline const uint32 getIndex() const { return mIndex; }
	inline void setIndex(const uint32 index)
	{
		if(index >= mFrames.size())
			return;

		mIndex = index;
	}
	virtual TweenFrame* getNextFrame(const uint32 time);

	inline const uint32 getLoopCount() const { return mLoopCount; }
	inline void setLoopCount(const uint32 count) { mLoopCount = count; }
	inline const uint8 getLoopType() const { return mLoopType; }
	inline void setLoopType(const uint8 type) { mLoopType = type; }

	virtual void tween();

	void setCallback(void (*callback)(const float, const float, const float, const float, float&))
	{
		SAFE_DELETE(mSignal);
		mSignal = new FunctorType;
		if(!mSignal)
			AltoThrow(Exception::ERR_MEMORY);

		mSlot = mSignal->Connect(callback);
	}

protected:
	virtual void onTick(const Event& e);
	bool isExists(Renderable* r);
	void setToInitial();
	void setStart();

protected:
	typedef ISignal_v5<const float, const float, const float, const float, float&> FunctorType;

	vector<Renderable*>			mRenderables;
	vector<TweenFrame>			mFrames;
	uint32						mIndex;
	Tickable*					mTickable;
	uint8						mLoopType;
	uint32						mLoopCount;

	map<Renderable*, Vector2D>	mInitialPositions;
	map<Renderable*, float>		mInitialRotations;
	map<Renderable*, Vector2D>	mInitialScales;

	map<Renderable*, Vector2D>	mStartPositions;
	map<Renderable*, float>		mStartRotations;
	map<Renderable*, Vector2D>	mStartScales;

	ISlot						mSlot;
	FunctorType*				mSignal;
};

//must be declared here
DECLARE_INSTANCE_TYPE(Tweenable)

#endif /* TWEENABLE_H_ */
